<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <TITLE>aCalcout - Array Calculation Output Record</TITLE>
</HEAD>
<BODY>

<H1>
aCalcout - Array Calculation Output Record</H1>


<!-- TOC -->
<H2>Contents</H2>

<DL>
<DT><A HREF="#INTRODUCTION"><B>1. </B>- Introduction</A></DT>

<DT><A HREF="#SCAN_PARAMETERS"><B>2. </B>- Scan Parameters</A></DT>

<DT><A HREF="#ARRAY_SIZE_PARAMETERS"><B>3. </B>- Array-size Parameters</A></DT>

<DT><A HREF="#INPUT_LINKS"><B>4. </B>- Input Links</A></DT>

<DT><A HREF="#EXPRESSIONS"><B>5. </B>- Expressions</A></DT>

<DT><A HREF="#OPERANDS"><B>5.1. </B>- Operands</A></DT>

<DT><A HREF="#ALGEBRAIC"><B>5.2. </B>- Algebraic Functions/Operators</A></DT>

<DT><A HREF="#TRIGONOMETRIC"><B>5.3. </B>- Trigonometric Functions</A></DT>

<DT><A HREF="#RELATIONAL"><B>5.4. </B>- Relational Operators</A></DT>

<DT><A HREF="#LOGICAL"><B>5.5. </B>- Logical Operators</A></DT>

<DT><A HREF="#BITWISE"><B>5.6. </B>- Bitwise Operators</A></DT>

<DT><A HREF="#SEPARATORS"><B>5.7. </B>- Separators</A></DT>

<DT><A HREF="#IF-ELSE"><B>5.8. </B>- If-Else Expression</A></DT>

<DT><A HREF="#ARRAY_SPECIFIC"><B>5.9. </B>- Array-specific Functions/Operators</A></DT>

<DT><A HREF="#ARGUMENT_ARRAY"><B>5.10. </B>- Argument-array Operators</A></DT>

<DT><A HREF="#MISCELLANEOUS"><B>5.11. </B>- Miscellaneous Operators</A></DT>

<DT><A HREF="#EXAMPLES"><B>5.12. </B>- Examples</A></DT>

<DT><A HREF="#OUTPUT_PARAMETERS"><B>6. </B>- Output Parameters</A></DT>

<DT><A HREF="#DISPLAY_PARAMETERS"><B>7. </B>- Display Parameters</A></DT>

<DT><A HREF="#ALARM_PARAMETERS"><B>8. </B>- Alarm Parameters</A></DT>

<DT><A HREF="#MONITOR_PARAMETERS"><B>9. </B>- Monitor Parameters</A></DT>

<DT><A HREF="#RUN-TIME_PARAMETERS"><B>10. </B>- Run-time Parameters</A></DT>

<DT><A HREF="#RECORD_SUPPORT"><B>11. </B>- Record Support Routines</A></DT>

<DT><A HREF="#INIT_RECORD">init_record</A></DT>

<DT><A HREF="#PROCESS">process</A></DT>

<DT><A HREF="#SPECIAL">special</A></DT>

<DT><A HREF="#GET_VALUE">get_value</A></DT>

<DT><A HREF="#GET_UNITS">get_units</A></DT>

<DT><A HREF="#GET_PRECISION">get_precision</A></DT>

<DT><A HREF="#GET_GRAPHIC_DOUBLE">get_graphic_double</A></DT>

<DT><A HREF="#GET_CONTROL_DOUBLE">get_control_double</A></DT>

<DT><A HREF="#GET_ALARM_DOUBLE">get_alarm_double</A></DT>

<DT><A HREF="#RECORD_PROCESSING"><B>12. </B>- Record Processing</A></DT>

<DT><A HREF="#PROCESS"><B>12.1. </B>- process()</A></DT>

<DT><A HREF="#EXEC_OUTPUT"><B>12.2. </B>- execOutput()</A></DT>
</DL>

<HR><A NAME="INTRODUCTION"></A>

<em> Note: Some aspects of this record, and of the calc engine that it uses, are
experimental.  While the scalar functions and operators are probably fairly
stable, array operators and functions described here are not guaranteed to exist
in future versions of this software, or to behave in exactly the same way.  For
example, the function that takes the derivative of an array currently expects a
single array argument, and constructs an artificial independent variable array;
probably a future version will require that two arrays be specified.  </em>

<H1>
1. Introduction</H1>

The Array Calculation Output or "aCalcout" record is derived from the sCalcout
(string calcout) record, which, in turn, is derived from the calcout record. The
aCalcout record extends the calcout record by supporting array operands and
expressions in addition to scalar operands and expressions. The record has 12
array fields (AA...LL) used as input variables for the expression, and it calls
an extended version of the EPICS calculation engine that knows about arrays. 
Soft device support supplied with the aCalcout record writes array or scalar
data to the record's output link, depending on the number of elements of the
field to which it is linked.

<P>Here's a sample MEDM display of some of the the aCalcout record fields.
<P><center><IMG SRC="userArrayCalc.adl.jpg"><br>userArrayCalc.adl</IMG></center>

<P>&nbsp;
<HR><A NAME="SCAN_PARAMETERS"></A>
<H1>
2. Scan Parameters</H1>

The aCalcout record has the standard fields for specifying under what
circumstances the record will be processed.  See the EPICS Record Reference
Manual for these fields and their use.

<P>&nbsp;
<HR><A NAME="ARRAY_SIZE_PARAMETERS"></A>
<H1>
3. Array-size Parameters</H1>

The aCalcout record allocates NELM elements for its arrays the first time they
are used. This is the maximum number of array elements, and it applies to all
arrays.  NELM must be specified at boot time, before any array is used.

<P>The number of elements actually used is specified as NUSE.  The value of NUSE
will forced into the range 0,NELM (inclusive).  If NUSE==0, the record will take
it as NELM.

<P>When a CA client connects to an array, the acalcout record can tell the
client that the array size is either NELM, or NUSE, depending on the setting of
the SIZE field, which takes values "NELM" and "NUSE".  "NELM" is the default,
and it's the safer choice.  "NELM" is less efficient than "NUSE", in some cases.
If SIZE is set to "NUSE", the CA connection must be broken and reestablished
when the NUSE field increases. 

<P><TABLE BORDER NOSAVE >
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
</TR>

<TR>
<TD>NELM</TD>
<TD>Number of allocated array elements</TD>
<TD>DBF_ULONG</TD>
<TD>Yes</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>NUSE</TD>
<TD>Number of array elements actually to be used</TD>
<TD>DBF_ULONG</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>SIZE</TD>
<TD>Specified whether NELM or NUSE is the array size declared to clients</TD>
<TD>MENU("NELM","NUSE")</TD>
<TD>Yes</TD>
<TD>"NELM"</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

</TABLE>

<P>&nbsp;

<P>&nbsp;
<HR><A NAME="INPUT_LINKS"></A>

<H1>
4. Input Links</H1>

The aCalcout record has 24 links with which it fetches values for use in expressions: 12 to
scalar fields (INPA -> A, INPB -> B, . . . INPL -> L); and 12 to array fields
(INAA -> AA, INBB -> BB, ...INLL -> LL). The fields can be database links,
channel access links, or (scalar-fields only) constants. These link fields
cannot be hardware addresses. In addition, the aCalcout record contains the
fields INAV, INBV, . . . INLV, which indicate the status of the links to scalar
fields, and the fields IAAV, IBBV, . . . ILLV, which indicate the status of the
links to array fields.&nbsp; These fields indicate whether or not the specified
PV was found and a link to it established. See <A HREF="#DISPLAY_PARAMETERS">Section 7,
<I>Display Parameters</I></A> for an explanation of these fields.

<P>&nbsp;See the EPICS Record Reference Manual for information on how to specify
database links.

<TABLE BORDER NOSAVE >
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
</TR>

<TR>
<TD>INPA</TD>
<TD>Input Link A</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>INPB</TD>
<TD>Input Link B</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>INPL</TD>
<TD>Input Link L</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>No</TD>
<TD>No</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>INAA</TD>
<TD>Input Link AA</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>INBB</TD>
<TD>Input Link BB</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>INLL</TD>
<TD>Input Link LL</TD>
<TD>INLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
</TR>

</TABLE>

<P>&nbsp;

<HR><A NAME="EXPRESSIONS"></A>
<H1>
5. Expressions</H1>

Like the Calcout record, the aCalcout record has a CALC field into which you can
enter an expression for the record to evaluate when it processes.  The resulting
scalar value will be placed in the VAL field, and the resulting array value
will be placed in the AVAL field.  VAL can then be used by the OOPT field (see
<A HREF="#EXPRESSIONS">Section 6, <I>Output Parameters</I></A>) to determine
whether or not to write to the output link or post an output event. Either VAL
and AVAL can also be written to the output link.  (If you elect to write an
output value, the record will choose between VAL and AVAL, depending on the data
type of the field at the other end of the output link.)

<P>The CALC expression is converted to opcodes and stored in postfix
notation in the RPCL field.  It is the postfix expression which is actually
evaluated when the record processes.  When the CALC field is changed at
run-time, the record-support routine <code>special()</code> calls a function
to check it and convert it to postfix.

<BR>The record also has a second set of calculation-related fields described in
<A HREF="#EXPRESSIONS">Section 6, <I>Output Parameters.</I></A>

<BR>&nbsp;
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>CALC</TD>
<TD>Calculation</TD>
<TD>STRING[80]</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>

<TR>
<TD>VAL</TD>
<TD>Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>

<TR>
<TD>RPCL</TD>
<TD>Postfix</TD>
<TD>NOACCESS</TD>
<TD>No</TD>
<TD>0</TD>
<TD>No</TD>
<TD>No</TD>
<TD>N/A</TD>
<TD>No</TD>
</TR>

<TR>
<TD>AVAL</TD>
<TD>Array value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>
</TABLE>

<P> Expressions supported by the array calculation record can involve scalar
and/or array operands, algebraic operators and functions, trigonometric
functions, relational operators, logical operators, array operators and
functions, parentheses and commas, and the conditional '?:' operator. All are
described in sections to follow, but first, we need to talk about how  operators
and functions behave when presented with scalar, array, and mixed operands.

<P>Unless otherwise stated, functions and operators behave as follows:

<ul>

<li>One-argument functions and operators, when given an array-valued argument or
operand, operate on each array element individually, and return an array.

<li>Two-argument functions and operators, when given array-valued operands,
operate on pairs of elements and return an array.  (e.g., <code>aa+bb =
aa[0]+bb[0], aa[1]+bb[1],...</code>)

<li>If one argument of a two-argument function or operator is an array, and the
other argument is a scalar, the scalar argument is converted to an array by
repeating the scalar value.  Thus, the value of the expression <code>A*BB</code> is the array
<code>a*bb[0], a*bb[1], a*bb[3],...</code>

<li>Whenever an array must be converted implicitly to a scalar (e.g., for the
operators <code>?:</code>, <code>^</code>, <code>**</code>, <code>>></code>, and
<code><<</code>), the scalar value used is the value of the first array
element.  In the following expressions, the array argument in <font
color='red'>color</font> will be converted implicitly to scalar:

<ul>
<li><font color='red'>AA</font>?BB:CC
<li>AA^<font color='red'>BB</font>
<li>AA**<font color='red'>BB</font>
<li>AA&gt;&gt;<font color='red'>BB</font>
<li>AA&lt;&lt;<font color='red'>BB</font>
</ul>

</ul> 

<A NAME="OPERANDS"></A>
<H2>
5.1. Operands</H2>

The expression can use the values retrieved from the input links as operands.
These values retrieved from the input links are stored in the A-L, and AA-LL
fields. The values to be used in the expression are simply referenced by the
field name. For example, the values obtained from the INPA link is stored in the
field A, and is referred to in an expression as 'A' (or 'a' -- case doesn't
matter).

<P>The number of elements of the array operands AA-LL is set at boot time by
the field NELM.  If an array value is received by the record with more or fewer
elements, the array used by the aCalcout record will be truncated or padded at
the end with zeros.


<P>
<TABLE BORDER>

<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>A</TD>
<TD>Input Value A</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>B</TD>

<TD>Input Value B</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>


<TR>
<TD>L</TD>
<TD>Input Value L</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR><TD></TR>

<TR>
<TD>AA</TD>
<TD>Input array AA</TD>
<TD>DOUBLE ARRAY</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>BB</TD>
<TD>Input array BB</TD>
<TD>DOUBLE ARRAY</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>LL</TD>
<TD>Input array LL</TD>
<TD>DOUBLE ARRAY</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes/No*</TD>
<TD>Yes</TD>
<TD>Yes</TD>
</TR>

</TABLE>

<P>* If a valid input link is associated with this field, then the record will
not not permit it to be modified by a 'put' operation.

<P>There are a few special operands not associated with input fields, but
defined by the record (more exactly, defined by the calc engine the record uses
to evaluate expressions).  All but <code>RNDM</code>, <code>NRNDM</code>, and <code>ARNDM</code> are
constants.

<table border>

<tr>
<td align=center valign=top>PI
<td valign=top>3.141592654

<tr>
<td align=center valign=top>D2R
<td valign=top>Degrees to radians (PI/180)

<tr>
<td align=center valign=top>R2D
<td valign=top>Radians to degrees (1/D2R)

<tr>
<td align=center valign=top>S2R
<td valign=top>Arc seconds to radians (D2R/3600)

<tr>
<td align=center valign=top>R2S
<td valign=top>Radians to arc seconds (1/S2R)

<tr>
<td align=center valign=top>NRNDM
<td valign=top>Random number from a normal (Gaussian) distribution about 0,
with a standard deviation of 1.

<tr>
<td align=center valign=top>RNDM
<td valign=top>Random number between 0 and 1.

<tr>
<td align=center valign=top>ARNDM
<td valign=top>Array of random numbers between 0 and 1.

<tr>
<td align=center valign=top>IX
<td valign=top>The array (0,1,2,...,NUSE).

<tr>
<td align=center valign=top>VAL
<td valign=top>The previous value of the VAL field.  (In an OCAL expression,
"VAL" is the previous value of the OVAL field.)

<tr>
<td align=center valign=top>AVAL
<td valign=top>The previous value of the AVAL field. (In an OCAL expression,
"AVAL" is the previous value of the OAV field.)

</table>


<A NAME="ALGEBRAIC"></A>
<A NAME="Expressions"></A>
<H2>
5.2. Algebraic Functions/Operators</H2> 

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>ABS
<td valign=top>Absolute value (one-argument function)
<td><code>ABS(A)</code>

<tr>
<td align=center valign=top>DBL
<td valign=top>Convert (array) to double (one-argument function)
<td><code>DBL(AA)</code>

<tr>
<td align=center valign=top>FINITE
<td valign=top>True if all arguments are finite (variable-argument function)
<td><code>FINITE(A,B,...)</code>

<tr>
<td align=center valign=top>ISINF
<td valign=top>True if argument is infinite (one-argument function)
<td><code>ISINF(A)</code>

<tr>
<td align=center valign=top>ISNAN
<td valign=top>True if argument is not a number (one-argument function)
<td><code>ISNAN(A)</code>

<tr>
<td align=center valign=top>SQRT
<td valign=top>Square root (one-argument function) (SQR is deprecated)
<td><code>SQRT(A)</code>

<tr>
<td align=center valign=top>MIN
<td valign=top>Minimum (variable-argument function)
<td><code>MIN(A,B,...)</code>

<tr>
<td align=center valign=top>MAX
<td valign=top>Maximum (variable-argument function)
<td><code>MAX(A,B,...)</code>

<tr>
<td align=center valign=top>CEIL
<td valign=top>Ceiling (one-argument function)
<td><code>CEIL(A)</code>

<tr>
<td align=center valign=top>FLOOR
<td valign=top>Floor (one-argument function)
<td><code>FLOOR(A)</code>

<tr>
<td align=center valign=top>INT
<td valign=top>Nearest integer (one-argument function)
<td><code>INT(A)</code>

<tr>
<td align=center valign=top>NINT
<td valign=top>Nearest integer (one-argument function)
<td><code>NINT(A)</code>

<tr>
<td align=center valign=top>APOS
<td valign=top>Positive component. If negative, then zero (one-argument function)
<td><code>APOS(A)</code>

<tr>
<td align=center valign=top>ANEG
<td valign=top>Negative component. If positive, then zero (one-argument function)
<td><code>ANEG(A)</code>

<tr>
<td align=center valign=top>LOG
<td valign=top>Log base 10 (one-argument function)
<td><code>LOG(A)</code>

<tr>
<td align=center valign=top>LN
<td valign=top>Natural logarithm (one-argument function)
<td><code>LN(A)</code>

<tr>
<td align=center valign=top>LOGE
<td valign=top>Deprecated synonym for 'LN'
<td><code>LOGE(A)</code>

<tr>
<td align=center valign=top>EXP
<td valign=top>Exponential function (unary)
<td><code>EXP(A)</code>

<tr>
<td align=center valign=top>^
<td valign=top>Exponential (binary) (Same as '**'.)
<td><code>A^B</code>

<tr>
<td align=center valign=top>**
<td valign=top>Exponential (binary) (Same as '^'.)
<td><code>A**B</code>

<tr>
<td align=center valign=top>+
<td valign=top>Addition (binary)
<td><code>A+B</code>

<tr>
<td align=center valign=top>-
<td valign=top>Subtraction (binary)
<td><code>A-B</code>

<tr>
<td align=center valign=top>*
<td valign=top>Multiplication (binary)
<td><code>A*B</code>

<tr>
<td align=center valign=top>/
<td valign=top>Division (binary)
<td><code>A/B</code>

<tr>
<td align=center valign=top>%
<td valign=top>Modulo (binary)
<td><code>A%B</code>

<tr>
<td align=center valign=top>-
<td valign=top>Negate (unary)
<td><code>-A</code>

<tr>
<td align=center valign=top>NOT
<td valign=top>Negate (unary)
<td><code>NOT A</code>

<tr>
<td align=center valign=top>&gt;&amp;
<td valign=top>Max (binary)
<td><code>A>?B</code>

<tr>
<td align=center valign=top>&lt;&amp;
<td valign=top>Min (binary)
<td><code>A&lt;?B</code>

</table>


<P>
<A NAME="TRIGONOMETRIC"></A>
<H2>
5.3. Trigonometric Functions</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>SIN
<td valign=top>Sine (one-argument function)
<td><code>SIN(A)</code>

<tr>
<td align=center valign=top>SINH
<td valign=top>Hyperbolic sine (one-argument function)
<td><code>SINH(A)</code>

<tr>
<td align=center valign=top>ASIN
<td valign=top>Arc sine (one-argument function)
<td><code>ASIN(A)</code>

<tr>
<td align=center valign=top>COS
<td valign=top>Cosine (one-argument function)
<td><code>COS(A)</code>

<tr>
<td align=center valign=top>COSH
<td valign=top>Hyperbolic cosine (one-argument function)
<td><code>COSH(A)</code>

<tr>
<td align=center valign=top>ACOS
<td valign=top>Arc cosine (one-argument function)
<td><code>ACOS(A)</code>

<tr>
<td align=center valign=top>TAN
<td valign=top>Tangent (one-argument function)
<td><code>TAN(A)</code>

<tr>
<td align=center valign=top>TANH
<td valign=top>Hyperbolic tangent (one-argument function)
<td><code>TANH(A)</code>

<tr>
<td align=center valign=top>ATAN
<td valign=top>Arc tangent (one-argument function)
<td><code>ATAN(A)</code>

<tr>
<td align=center valign=top>ATAN2
<td valign=top>Alternate form of arctangent (two-argument function)
<td><code>ATAN2(A,B)</code>

</table>

<P>
<A NAME="RELATIONAL"></A>
<H2>
5.4. Relational Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>>=
<td valign=top>Greater than or equal to
<td><code>A&gt;=B</code>

<tr>
<td align=center valign=top>>
<td valign=top>Greater than
<td><code>A&gt;B</code>

<tr>
<td align=center valign=top>&lt;=
<td valign=top>Less than or equal to
<td><code>A&lt;=B</code>

<tr>
<td align=center valign=top>&lt;
<td valign=top>Less than
<td><code>A&lt;B</code>

<tr>
<td align=center valign=top>!=
<td valign=top>Not equal to (same as '#')
<td><code>A!=B</code>

<tr>
<td align=center valign=top>#
<td valign=top>Not equal to (same as '!=')
<td><code>A#B</code>

<tr>
<td align=center valign=top>==
<td valign=top>Equal to (same as '=')
<td><code>A==B</code>

<tr>
<td align=center valign=top>=
<td valign=top>Equal to (same as '==')
<td><code>A=B</code>

</table>

<P>
<A NAME="LOGICAL"></A>
<H2>
5.5. Logical Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>&amp;&amp;
<td valign=top>Logical AND
<td><code>A&amp;&amp;B</code>

<tr>
<td align=center valign=top>||
<td valign=top>Logical OR
<td><code>A||B</code>

<tr>
<td align=center valign=top>!
<td valign=top>Logical NOT
<td><code>!A</code>

</table>

<P>
<A NAME="BITWISE"></A>
<H2>
5.6. Bitwise Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>|
<td valign=top>Bitwise OR
<td><code>A|B</code>

<tr>
<td align=center valign=top>OR
<td valign=top>Bitwise OR
<td><code>A OR B</code>

<tr>
<td align=center valign=top>&amp;
<td valign=top>Bitwise AND
<td><code>A&amp;B</code>

<tr>
<td align=center valign=top>AND
<td valign=top>Bitwise AND
<td><code>A AND B</code>

<tr>
<td align=center valign=top>XOR
<td valign=top>Bitwise Exclusive OR
<td><code>A XOR B</code>

<tr>
<td align=center valign=top>~
<td valign=top>One's Complement
<td><code>~A</code>

<tr>
<td align=center valign=top>&lt;&lt;
<td valign=top>Left shift
<td><code>A&lt;&lt;B</code>

<tr>
<td align=center valign=top>&gt;&gt;
<td valign=top>Right shift
<td><code>A&gt;&gt;B</code>
</table>


<P>
<A NAME="SEPARATORS"></A>
<H2>
5.7. Separators</H2>

The open and close parentheses are supported.  Nested parenthesis are supported.
Square and curly brackets are not available for use as separators, because they
are being used as operators.

<BR>The comma is supported when used to separate the arguments of a binary
function.

<br>Spaces may occur between expression elements.  Space is required between
elements that would otherwise be parsed incorrectly.  The parser always attempts
to match the largest string of characters that constitute a recognized operator
or variable. For example, <code>A AND B</code> could be shortened to <code>A ANDB</code>,
because <code>ANDB</code> will be parsed as <code>AND B</code>.  However,
<code>A AND B</code> may not be shortened to <code>AAND B</code>, because
<code>AAND</code> would be parsed as <code>AA ND</code>.

<P><A NAME="IF-ELSE"></A>
<H2>
5.8. If-Else Expression</H2>
The C language's if-else ("<code>?:</code>") operator is supported. The format is:

<PRE>&nbsp;&lt;expression&gt; ? &lt;expression-true result&gt; : &lt;expression-false  result&gt;</PRE>


<P>
<A NAME="ARRAY_SPECIFIC"></A>
<H2>
5.9. Array-specific Functions/Operators</H2>

Most of the functions and operators that can work with arrays are simple
generalizations of functions and operators that work with scalars. Such
functions are not listed here.  In this section are those functions or operators
that apply only to arrays, and whose behavior is not a simple element-by-element
rendition of some scalar function.

<P><table border>
<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>[
<td>Subarray
<td><code>AA[1,3] -> aa(1),aa(2),aa(3)</code>

<tr>
<td align=center valign=top>{
<td>Subarray in place 
<td><code>AA[1,3] -> 0, aa(1),aa(2),aa(3), 0,...</code>

<tr>
<td align=center valign=top>&gt;&gt;
<td>Array shift right.  Move array elements by index.  If index is not an integer,
the array is interpolated to move by the fractional part.
<td><code>AA&gt;&gt;2</code>

<tr>
<td align=center valign=top>&lt;&lt;
<td>Array shift left.    Move array elements by index.  If index is not an integer,
the array is interpolated to move by the fractional part.
<td><code>AA&lt;&lt;2</code> (same as <code>AA&gt;&gt;-2</code>)

<tr>
<td align=center valign=top>AMIN
<td valign=top>Minimal element of array (one-argument function)
<td><code>AMIN(AA) -> scalar</code>

<tr>
<td align=center valign=top>AMAX
<td valign=top>Maximal element of array (one-argument function)
<td><code>AMAX('a','b','c') -> 'c'</code>

<tr>
<td align=center valign=top>ARR
<td>Convert argument to array (one-argument function)
<td><code>ARR(1) -> 1, 1, 1,...</code>

<tr>
<td align=center valign=top>AVG
<td valign=top>Average of array values

<td><code>AVG(AA)=SUM(AA)/arraySize</code>
<code>AVG(AA[4,9])=SUM(AA[4,9])/6</code>

<tr>
<td align=center valign=top>CAT

<td valign=top>Concatenate array subranges, or an array subrange and a double
value.  If the second argument is a scalar, it is not converted to an array
before being appended to the first argument.  Note that CAT does nothing if its
first argument is not a subrange, because a full array has no free space in
which to append new values.

<td><code>CAT(AA[0,2],BB[0,2])</code>
<code>CAT(AA[0,2],B)</code>

<tr>
<td align=center valign=top>CUM
<td valign=top>Running sum of array values.  For example, if AA=(1,2,3),
CUM(AA)=(1,3,6).
<td><code>CUM(AA)</code>

<tr>
<td align=center valign=top>DERIV
<td valign=top>Derivative of array values, with respect to array index.
Equivalent to NDERIV(AA,2).
<td><code>DERIV(AA)</code>

<tr>
<td align=center valign=top>FWHM
<td valign=top>Full width at half max of array values
<td><code>FWHM(AA)</code>

<tr>
<td align=center valign=top>FITPOLY
<td valign=top>(Deprecated.  Use FITQ.) Fit array to second order polynomial a + b*x + c*x^2.
<td><code>FITPOLY(AA)</code>

<tr>
<td align=center valign=top>FITMPOLY
<td valign=top>(Deprecated.  Use FITMQ.) Fit masked array to second order polynomial.  First argument is input-data
array, second argument is the mask array.  If mask-array element value is true (greater than zero),
corresponding data-array element will be used to compute best-fit polynomial a + b*x + c*x^2.
<td><code>FITPOLY(AA,AA>0)</code>

<tr>
<td align=center valign=top>FITQ

<td valign=top>Fit array to quadratic a + b*x + c*x^2, and optionally return fit
coefficients.  If the second, third, and fourth arguments are specified as the
names of double variables, fit coefficients will be stored to those
acalcoutRecord fields, in the order a,b,c. If any of the second, third, and
fourth arguments is an array variable, it will be ignored.

<td><code>FITQ(AA)</code><br><code>FITQ(AA,J,K,L)</code>

<tr>
<td align=center valign=top>FITMQ

<td valign=top>Fit masked array to quadratic, and optionally return fit
coefficients.  First argument is input-data array, second argument is the mask
array.  If mask-array element value is true (greater than zero), corresponding
data-array element will be used to compute best-fit polynomial a + b*x + c*x^2.
If the third, fourth, and fifth arguments are specified as the names of double
variables, fit coefficients will be stored to those acalcoutRecord fields, in
the order a,b,c. If any of the second, third, and fourth arguments is an array
variable, it will be ignored.

<td><code>FITMQ(AA,AA>0)</code><br><code>FITMQ(AA,AA>0,J,K,L)</code>

<tr>
<td align=center valign=top>IX
<td valign=top>The array (0,1,2,3,...,NUSE)
<td><code>IX(AA)</code>

<tr>
<td align=center valign=top>IXMAX
<td valign=top>The index of the largest (most positive) element of the array.
<td><code>IXMAX(AA)</code>

<tr>
<td align=center valign=top>IXMIN
<td valign=top>The index of the smallest (most negative) element of the array.
<td><code>IXMIN(AA)</code>

<tr>
<td align=center valign=top>IXZ
<td valign=top>The (floating-point) index of the first zero crossing in the array, calculated by
linear interpolation.
<td><code>IXZ(AA)</code>

<tr>
<td align=center valign=top>IXNZ
<td valign=top>The index of the first nonzero element of the array.  (The first
element whose absolute value is greater than 1.e-9.)
<td><code>IXNZ(AA)</code>

<tr>
<td align=center valign=top>NDERIV
<td valign=top>Derivative of array values, with respect to array index.
Derivative is calculated in the following way: at each array point, fit
N surrounding array points to a second-order polynomial, take the derivative
of the polynomial analytically, and evaluate it at the index of the array
point.  The number of points, on either side of the array point, to be used
in the fit, is specified by the second argument to NDERIV().  (I.e., if N is
specified, 2*N+1 points will be fit.)  Array elements less than N points from
the beginning or end of the array will get a less effectively calculated
derivative, since the fit will not be centered on the point.
<td><code>NDERIV(AA,B)</code>

<tr>
<td align=center valign=top>NSMOO
<td valign=top>Smooth array values, using multiple applications of SMOO()
<td><code>NSMOO(AA,B)</code>

<tr>
<td align=center valign=top>STD
<td valign=top>Standard deviation of array values
<td><code>STD(AA)</code>

<tr>
<td align=center valign=top>SMOO
<td valign=top>Smooth array values, using a 5-point binomial formula
y'(i) = y(i-2)/16 + y(i-1)/4 + 3*y(i)/8 + y(i+1)/4 + y(i+2)/16
<td><code>SMOO(AA)</code>

<tr>
<td align=center valign=top>SUM
<td valign=top>Sum of array values.
<td><code>SUM(AA)</code>

</table>

<A NAME="ARGUMENT_ARRAY"></A>
<H2>
5.10. Argument-array Operators</H2>
<table border>

<P>These operators represent the scalar/array fields of the aCalcout record as
arrays of scalars/arrays.  They are an alternative way of specifying
the fields A-L and AA-LL.

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Example

<tr>
<td align=center valign=top>@
<td>Scalar array element.  Regard the numeric fields A-L as an array whose
elements are numbered 0-11, and return the element whose number follows.
Thus, <code>@0</code> is another way of saying <code>A</code>.
(unary operator)
<td><code>@A</code>

<tr>
<td align=center valign=top>@@
<td>Array array element.  Regard the array fields AA-LL as an array of arrays whose
elements are numbered 0-11, and return the element whose number follows.
Thus, <code>@@1</code> is another way of saying <code>BB</code>.
  (unary operator)
<td><code>@@A</code>

</table>

<A NAME="MISCELLANEOUS"></A>
<H2>
5.11. Miscellaneous Operators</H2>

<table border>

<tr>
<th align=center valign=top>Op
<th valign=top>Description
<th valign=top>Examples

<tr>
<td align=center valign=top>:=
<td>Store value of right hand side in location specified by left hand side.  (binary)
<td><code>A:=1.2</code>
<code><BR>@7:=3</code>
<code><BR>AA:=IX</code>
<code><BR>@@4:=sin(IX)</code>

<tr>
<td align=center valign=top>UNTIL
<td>Execute expression until its value is TRUE.  (binary)<br>

The total number of iterations is limited to the ioc-shell variable
sCalcLoopMax, which defaults to 1000.

<td><code>until(1)</code>
<code><BR>until(a:=a+1;b:=b-1;b<1)</code>

</table>


<A NAME="EXAMPLES"></A>
<H2>
5.12. Examples</H2>
<H3>Algebraic</H3>

<DL>
<DT><B><CODE>A + B + 10</B></CODE>
<DD>Result is <CODE>A + B + 10</CODE>
</DL>

<hr>
<H3>Relational</H3>

<DL>
<DT><b><CODE>(A + B) &lt; (C + D)</CODE></b>
<DD>Result is <CODE>1</CODE> if <CODE>(A+B) &lt; (C+D)</CODE>
<BR>Result is <CODE>0</CODE> if <CODE>(A+B) >= (C+D)</CODE>
</DL>

<hr>
<H3>If-Else</H3>

<DL>
<DT><b><CODE>(A+B)&lt;(C+D)?E:F+L+10</CODE></b>
<DD>Result is <CODE>E</CODE> if <CODE>(A+B) &lt; (C+D)</CODE>
<BR>Result is <CODE>F+L+10</CODE> if <CODE>(A+B) >= (C+D)</CODE>

<P><DT><b><CODE>(A+B)&lt;(C+D)?E</CODE></b>
<DD>Result is <CODE>E</CODE> if (A+B) &lt; (C+D)
<BR>Result is unchanged if <CODE>(A+B) >= (C+D)</CODE>
</DL>

<hr>
<H3>Logical</H3>

<DL>
<DT><b><CODE>A&amp;B</CODE></b>
<DD>Causes the following to occur:

<OL>
<LI>Convert <CODE>A</CODE> to integer
<LI>Convert <CODE>B</CODE> to integer
<LI>Perform bit-wise <CODE>AND</CODE> of <CODE>A</CODE> and <CODE>B</CODE>
<LI>Convert result to floating point
</OL>
</DL>

<hr>
<H3>Array</H3>
<P>Notation:  I'll use <code>(1,2,3)</code> to indicate an array.  Note that
[1,2] is not an array, but the subrange operator with arguments 1 and 2.
The subrange operator must follow an array, like so: <code>AA[2,5]</code>.
Similarly, {1,2} is not an array, but the subrange-in-place operator.

<DL>
<DT><B><CODE>A + AA</CODE></B><br>
where A=1 and AA = (1,2,3)
<DD>Result is <CODE>(2,3,4)</CODE>.

<P><DT><B><CODE>A + DBL(AA)</CODE></B><br>
where A=1 and AA=(1,2,3)
<DD>Result is <CODE>2</CODE>.  DBL returns the first array element.

<P><DT><B><CODE>AA+BB</CODE></B><br>
where AA=(1,2,3) and BB=(7,8,9)
<DD>Result is <CODE>(8,10,12)</CODE>.  Element-by-element sum.  Most operators
behave in this way.

<P><DT><B><CODE>AA[2,4]</CODE></B><br>
where AA = (1,2,3,4,5)
<DD>Result is <CODE>(3,4,5)</CODE>.&nbsp; (The first element of an array is
numbered "0".)

<P><DT><B><CODE>AA[-3,-1]</CODE></B><br>
where AA=(1,2,3,4)
<DD>Result is <CODE>(2,3,4)</CODE>.&nbsp; (The last element of an array is
numbered "-1".)

<P><DT><B><CODE>AA{2,4}</CODE></B><br>
where AA = (1,2,3,4,5,6)
<DD>Result is <CODE>(0,0,3,4,5,0)</CODE>.&nbsp; (Similar to the [] operator,
but the selected subrange is left in place.)

</DL>

<hr>
<H3>
Argument array</H3>

<DL>
<DT><B><CODE>@0</CODE></B>
<DD>Result is the value of the numeric variable <CODE>A</CODE>.  ("<CODE>@0</CODE>"
is just another name for <CODE>A</CODE>.)<P>

<DT><B><CODE>@@0</CODE></B>
<DD>Result is the value of the array variable AA.<P>

<DT><B><CODE>@(A+B)</CODE></B>
<DD>Result is the value of the numeric variable whose number is given by the sum
of A and B.<P>

<DT><B></B>
<DD>
<P>
</DL>

<hr>
<H3>Store</H3>

The "Store" operator is the only array-calc operator that does not produce a
value.  Thus, the expression <B><code>a:=0</code></B> is an incomplete and therefore illegal calc expression,
because it leaves us with nothing to write to the record's <code>VAL</code> field.

<DL>
<DT><B><CODE>A:=A-1;7</CODE></B>

<DD>Evaluate the expression <CODE>A-1</CODE>, store the result in the input
variable <CODE>A</CODE>, set the VAL field to 7.<P>

<DT><B><CODE>@0:=A-1;7</CODE></B>
<DD>Same as above, because <CODE>@0</CODE> is just another name for <CODE>A</CODE><P>

<DT><B><CODE>D:=0;@D:=A-1;7</CODE></B>
<DD>Same as above, because <CODE>D==0</CODE>.<P>

<DT><B><CODE>AA:=IX;7</CODE></B>
<DD>Overwrite the array input variable <CODE>AA</CODE> with the array (0,1,2...), and set the VAL field to 7.<P>

<DT><B><CODE>AA:=IX;b:=0;1</CODE></B>

<DD>Multiple store expressions, separated by ';' terminators, are legal at top
level, but - as always - the expression as a whole must produce a value.  This expression
produces the value <code>1</code>.<P>

<DT><B><CODE>A+(AA:="abc";b:=0;1)</CODE></B>

<DD>Multiple store expressions are also legal within parentheses, and again the
parenthesized subexpression must produce a value.  The parenthesized
subexpression in this example produces the value <code>1</code>, which is added to
<code>A</code>.<P>

<DT><B><CODE>@0:=A-1;7</CODE></B>

<DD>Evaluate the expression <CODE>A-1</CODE>, store the result in the input
variable <CODE>A</CODE>, and set the VAL field to 7.<P>
</DL>

<hr>
<H3>Loop ("UNTIL")</H3>

The <code>UNTIL</code> function evaluates its expression repeatedly until the
expression returns a nonzero value, or the allowed number of iterations
<code>sCalcLoopMax</code> has been reached.  When looping is done, or aborted,
the expression value is returned.

<DL>
<DT><B><CODE>UNTIL(1)</CODE></B>

<DD>The expression 1 is evaluated, terminates the loop, and is returned.  This
do-nothing expression is equivalent to <code>(1)</code>.<P>

<DT><B><CODE>B:=10;UNTIL(B:=B-1;B<1)</CODE></B> <DD>This do-almost-nothing
expression initializes B to 10, decrements it repeatedly until its value is
zero, and returns the value 1 (True).<P>

<DT><B><CODE>BB:=1; B:=1; AA:=BB; UNTIL(AA:=AA+(BB>>B); B:=B+1; B>10)</CODE></B>

<DD>Initialize <CODE>BB</CODE> to <CODE>(1,1,1...)</CODE>.  Loop to integrate
over <CODE>BB</CODE>, so that the N'th element of <CODE>AA</CODE> will be the
sum of all elements of <CODE>BB[0,N]</CODE>.<P> This expression is useful for
converting an array of step pulses accumulated by a multichannel scaler into an
array of positions at which the multichannel scaler's channel-advance signal was
triggered.  (The "CUM" function does this operation.)<P>

<DT><B><CODE>AA:=0;L:=0;UNTIL(AA:=CAT(AA[0,L],@L);L:=L+1;L>9);AA:=AA<<1</CODE></B>
<DD>Copy the 10 scalar input fields <code>A-J</code> to the first 10 elements of the array <code>AA</code>.<P>
(This quite an inefficient way to do the job.  An asub record would be much more efficient.)<P>

<DT><B><CODE>L:=0;AA:=IX;UNTIL(@L:=AA[L,L];L:=L+1;L>10)</CODE></B>

<dd>Copy the first 10 elements of <code>AA</code> to the scalar input variables <code>A-J</code>.<P>
(Again, this is quite an inefficient way to do the job.)

</DL>

<hr>
<P>Here's a more complete example of array calcs in use.  Suppose we want to
analyze results from a series of edge scans to find the conditions that produce
the sharpest edge.  Lacking any hardware, we'll also have to make fake data to
analyze.  We'll use three aCalcout records:
<ul>
<li><code>aCalc1</code> to compute artificial edge-scan data,
<li><code>aCalc2</code> to take the derivative of that data,
<li><code>aCalc3</code> to compute the FWHM of the derivative.
</ul>

<P>Here are field values that do the job:

<ul>
<pre>
aCalc1.CALC = "tanh((ix-a)/b)+c*arndm"
aCalc1.A = &lt;edge position&gt;
aCalc1.B = &lt;edge width control&gt;
aCalc1.C = &lt;amount of noise added to data&gt;
aCalc1.OUT = "aCalc2.AA PP"

aCalc2.CALC = "nderiv(aa,20)"
aCalc2.OUT = "aCalc3.AA PP"

aCalc3.CALC = "fwhm(aa)"
</pre>
</ul>


<P>&nbsp;
<HR><A NAME="OUTPUT_PARAMETERS"></A>
<H1>
6. Output Parameters</H1>

These parameters specify and control the output capabilities of the
aCalcout record. They determine when to write the output, where to write
it, and what the output will be. The OUT link specifies the Process Variable
to which the result will be written. The OOPT field determines the condition
that causes the output link to be written to. It's a menu field that has
six choices:

<P><table border>
<tr><td valign=top>
<TT>Every Time</TT><td valign=top>write output every time record is processed.


<tr><td valign=top>
<TT>On Change</TT><td valign=top>write output every time VAL changes, i.e., every
time the result of the expression changes.


<tr><td valign=top>
<TT>When Zero</TT><td valign=top>when record is processed, write output if VAL is
zero.


<tr><td valign=top>
<TT>When Non-zero</TT><td valign=top>when record is processed, write output if VAL
is non-zero.


<tr><td valign=top>
<TT>Transition to Zero</TT><td valign=top>when record is processed, write output only
if VAL is zero and last value was non-zero.


<tr><td valign=top>
<TT>Transition to Non-zero</TT><td valign=top>when record is processed, write output
only if VAL is non-zero and last value was zero.

<tr><td valign=top>
<TT>Never</TT><td valign=top>Don't write output ever.

</table>


<P>&nbsp;

The DOPT field determines what data is written to the output link when the
output is executed. The field is a menu field with two options: <TT>Use
CALC</TT> or <TT>Use OCAL</TT>. If <TT>Use CALC</TT> is specified, when the
record writes its output it will write the result of the expression in the CALC
field, that is, it will write the value of the VAL [AVAL] field to a scalar
[array] destination. If <TT>Use OCAL</TT> is specified, the record will instead
write the result of the expression in the OCAL field, which result is contained
in the OVAL field (array result in the OAV field). The OCAL field is exactly
analogous to the CALC field and has the same functionality: it can contain an
expression which is evaluated at run-time. Thus, if necessary, the record can
use the result of the CALC expression to determine if data should be written and
can use the result of the OCAL expression as the data to write.

<P>&nbsp;If the OEVT field specifies a non-zero integer and the condition in the
OOPT field is met, the record will post a corresponding event. If the ODLY field
is non-zero, the record pauses for the specified number of seconds before
executing the OUT link or posting the output event. During this waiting period
the record is "active" and will not be processed again until the wait is over.
The field DLYA is equal to 1 during the delay period. The resolution of the
delay entry is one clock tick, where the clock frequency is defined elsewhere
(see <code>epicsThreadSleepQuantum()</code> in the <i>EPICS Application Developer's Guide</i>).


<P>&nbsp;The IVOA field specifies what action to take with the OUT link
if the aCalcout record enters an INVALID alarm status. The options are
<TT>Continue normally</TT>, <TT>Don't drive outputs</TT>, and <TT>Set output
to IVOV</TT>. If the IVOA field is <TT>Set output to IVOV</TT>, the data
entered into the IVOV field is written to the OUT link if the record alarm
severity is INVALID.

<P>
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>OUT</TD>
<TD>Output Specification</TD>
<TD>OUTLINK</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>N/A</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OOPT</TD>
<TD>Output Execute Option</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>DOPT</TD>
<TD>Output Data Option</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OCAL</TD>
<TD>Output Calculation</TD>
<TD>STRING[36]</TD>
<TD>Yes</TD>
<TD>Null</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OVAL</TD>
<TD>Output Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OEVT</TD>
<TD>Event To Issue</TD>
<TD>SHORT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>ODLY</TD>
<TD>Output Execution Delay</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>IVOV</TD>
<TD>Invalid Output Action</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>IVOA</TD>
<TD>Invalid Output Value</TD>
<TD>DOUBLE</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OAV</TD>
<TD>Output array value</TD>
<TD>DOUBLE ARRAY</TD>
<TD>NO</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>

<TR>
<TD>WAIT</TD>
<TD>Wait for completion?</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>"NoWait"</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
</TR>
</TABLE>

<P> The aCalcout record uses device support to write to the
<code>OUT</code> link. Soft device supplied with the record is selected with
the .dbd specification <PRE> field(DTYP,"Soft Channel") </PRE>

This device support uses the record's <code>WAIT</code> field to determine
whether to wait for completion of processing initiated by the <code>OUT</code>
link before causing the record to execute its forward link.  The mechanism by
which this waiting for completion is performed requires that the
<code>OUT</code> link have the attribute <code>CA</code> -- i.e., the link text
looks something like

<p><code>  xxx:record.field <b>CA</b> NMS</code>

<p>Currently, the record does not try to ensure that <code>WAIT</code> and
<code>OUT</code> are compatibly configured.  If <code>WAIT</code> == "Wait",
but the link looks like

<p><code> xxx:record.field <b>PP</b> NMS</code>

<p>for example, then the record will not wait for completion before executing
its forward link.

<P>&nbsp;
<HR>
<P><A NAME="DISPLAY_PARAMETERS"></A>
<H1>
7. Display Parameters</H1>

These parameters are used to present meaningful data to the operator.
Some are also meant to represent the status of the record at run-time.
An example of an interactive MEDM display screen that displays the status
of the aCalcout record is located here.

<P>The EGU field contains a string of up to 16 characters which is
supplied by the user and which describes the values being operated upon.
The string is retrieved whenever the routine <TT>get_units</TT> is called.
The EGU string is solely for an operator's sake and does not have to be
used.

<P>The HOPR and LOPR fields only refer to the limits of the VAL,
HIHI, HIGH, LOW, and LOLO fields. PREC controls the precision of the VAL
field.

<P>The INAV-INLV and IAAV-ILLV fields indicate the status of the
link to the PVs specified in the INPA-INPL and INAA-INLL fields, respectively.
The fields can have three possible values:

<P>&nbsp;
<table border>

<tr>
<td valign=top>Ext PV NC
<td valign=top>the PV wasn't found on this IOC and a Channel Access link hasn't
been established.
</tr>

<tr>
<td valign=top>Ext PV OK
<td valign=top>the PV wasn't found on this IOC and a Channel Access link has
been established.
</tr>

<tr>
<td valign=top>Local PV
<td valign=top>the PV was found on this IOC.
</tr>

<tr>
<td valign=top>Constant
<td valign=top>the corresponding link field is a constant.
</tr>

</table>

<P>The OUTV field indicates the status of the OUT link. It has the same possible
values as the INAV-INLV fields.

<P>The CLCV and OLCV fields indicate the validity of the expression
in the CALC and OCAL fields, respectively. If the expression is invalid,
the field is set to one.

<P>The DLYA field is set to one during the delay interval specified
in ODLY.

<P>See the EPICS Record Reference Manual, for more on the record name (NAME) and
description (DESC) fields.

<P>
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>EGU</TD>
<TD>Engineering Units</TD>
<TD>STRING [16]</TD>
<TD>Yes</TD>
<TD>Null</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>PREC</TD>
<TD>Display Precision</TD>
<TD>SHORT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>HOPR</TD>
<TD>High Operating Range</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>LOPR</TD>
<TD>Low Operating Range</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>INAV</TD>
<TD>Link Status of INPA</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>INBV</TD>
<TD>Link Status of INPB</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>INLV</TD>
<TD>Link Status of INPL</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OUTV</TD>
<TD>OUT PV Status</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>CLCV</TD>
<TD>CALC Valid</TD>
<TD>LONG</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>OCLV</TD>
<TD>OCAL Valid</TD>
<TD>LONG</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>DLYA</TD>
<TD>Output Delay Active</TD>
<TD>USHORT</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>NAME</TD>
<TD>Record Name</TD>
<TD>STRING [29]</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>DESC</TD>
<TD>Description</TD>
<TD>STRING [29]</TD>
<TD>Yes</TD>
<TD>Null</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>IAAV</TD>
<TD>Link Status of INAA</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>IBBV</TD>
<TD>Link Status of INBB</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>ILLV</TD>
<TD>Link Status of INLL</TD>
<TD>Menu</TD>
<TD>No</TD>
<TD>1</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>
</TABLE>
&nbsp;

<HR>
<P><A NAME="ALARM_PARAMETERS"></A>
<H1>
8. Alarm Parameters</H1>

The possible alarm conditions for the aCalcout record are the SCAN,
READ, Calculation, and limit alarms. The SCAN and READ alarms are called
by the record support routines. The Calculation alarm is called by the
record processing routine when the CALC expression is an invalid one, upon
which an error message is generated.

<P>&nbsp;The following alarm parameters which are configured by the user
define the limit alarms for the VAL field and the severity corresponding
to those conditions.

<P>&nbsp;The HYST field defines an alarm deadband for each limit. See the
EPICS Record Reference Manual for a complete explanation of alarms
and these fields. 

<P>
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>HIHI</TD>
<TD>Hihi Alarm Limit</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>HIGH</TD>
<TD>High Alarm Limit</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>LOW</TD>
<TD>Low Alarm Limit</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>LOLO</TD>
<TD>Lolo Alarm Limit</TD>
<TD>FLOAT</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>HHSV</TD>
<TD>Severity for a Hihi Alarm</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>HSV</TD>
<TD>Severity for a High Alarm</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>LSV</TD>
<TD>Severity for a Low Alarm</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>LLSV</TD>
<TD>Severity for a Lolo Alarm</TD>
<TD>Menu</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>Yes</TD>
</TR>

<TR>
<TD>HYST</TD>
<TD>Alarm Deadband</TD>
<TD>DOUBLE</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

</TABLE>
&nbsp;

<HR>
<P><A NAME="MONITOR_PARAMETERS"></A>
<H1>
9. Monitor Parameters</H1>

These parameters are used to determine when to send monitors for the
value fields. The monitors are sent when the value field exceeds the last
monitored field by the appropriate deadband, the ADEL for archiver monitors
and the MDEL field for all other types of monitors. If these fields have
a value of zero, every time the value changes, monitors are triggered;
if they have a value of -1, every time the record is scanned, monitors
are triggered.

<TABLE BORDER >
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>ADEL</TD>
<TD>Archive Deadband</TD>
<TD>DOUBLE</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>MDEL</TD>
<TD>Monitor, i.e. value change, Deadband</TD>
<TD>DOUBLE</TD>
<TD>Yes</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

</TABLE>
&nbsp;

<HR>
<P><A NAME="RUN-TIME_PARAMETERS"></A>
<H1>
10. Run-time Parameters</H1>

These fields are not configurable using a configuration tool and none
are modifiable at run-time. They are used to process the record.

<P>&nbsp;The LALM field is used to implement the hysteresis factor for
the alarm limits.

<P>&nbsp;The LA-LL fields are used to decide when to trigger monitors for
the corresponding fields. For instance, if LA does not equal the value
for A, monitors for A are triggered. The MLST and MLST fields are used
in the same manner for the VAL field.

<P>
<TABLE BORDER>
<TR>
<TH>Field</TH>
<TH>Summary</TH>
<TH>Type</TH>
<TH>DCT</TH>
<TH>Initial</TH>
<TH>Access</TH>
<TH>Modify</TH>
<TH>Rec Proc Monitor</TH>
<TH>PP</TH>
</TR>

<TR>
<TD>LALM</TD>
<TD>Last Alarmed Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>ALST</TD>
<TD>Archive Last Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>MLST</TD>
<TD>Monitor Last Value</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>LA</TD>
<TD>Previous Input Value for A</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>LB</TD>
<TD>Previous Input Value for B</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>LL</TD>
<TD>Previous Input Value for A</TD>
<TD>DOUBLE</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
</TR>

<TR>
<TD>LAA</TD>
<TD>Previous Input Value for AA</TD>
<TD>DOUBLE ARRAY</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>LBB</TD>
<TD>Previous Input Value for BB</TD>
<TD>DOUBLE ARRAY</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

<TR>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
<TD>...</TD>
</TR>

<TR>
<TD>LLL</TD>
<TD>Previous Input Value for LL</TD>
<TD>DOUBLE ARRAY</TD>
<TD>No</TD>
<TD>0</TD>
<TD>Yes</TD>
<TD>No</TD>
<TD>No</TD>
<TD>No</TD>
</TR>

</TABLE>
&nbsp;

<HR>
<P><A NAME="RECORD_SUPPORT"></A>
<H1>
11. Record Support Routines</H1>

<A NAME="INIT_RECORD"></A>
<H3>
init_record</H3>
For each constant input link, the corresponding value field is initialized
with the constant value if the input link is CONSTANT or a channel access
link is created if the input link is PV_LINK.

<P>&nbsp;A routine postfix is called to convert the infix expression in
CALC and OCAL to reverse polish notation. The result is stored in RPCL
and ORPC, respectively.

<P>&nbsp;<A NAME="PROCESS"></A>
<H3>
process</H3>
See section 12.

<P>&nbsp;<A NAME="SPECIAL"></A>
<H3>
special</H3>
This is called if CALC or OCAL is changed. special calls aCalcPostfix.

<P>&nbsp;<A NAME="GET_VALUE"></A>
<H3>
get_value</H3>
Fills in the values of struct valueDes so that they refer to VAL.

<P>&nbsp;<A NAME="GET_UNITS"></A>
<H3>
get_units</H3>
Retrieves EGU.

<P>&nbsp;<A NAME="GET_PRECISION"></A>
<H3>
get_precision</H3>
Retrieves PREC.

<P>&nbsp;<A NAME="GET_GRAPHIC_DOUBLE"></A>
<H3>
get_graphic_double</H3>
Sets the upper display and lower display limits for a field. If the field
is VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR,
else if the field has upper and lower limits defined they will be used,
else the upper and lower maximum values for the field type will be used.

<P>&nbsp;<A NAME="GET_CONTROL_DOUBLE"></A>
<H3>
get_control_double</H3>
Sets the upper control and the lower control limits for a field. If the
field is VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and
LOPR, else if the field has upper and lower limits defined they will be
used, else the upper and lower maximum values for the field type will be
used.

<P>&nbsp;<A NAME="GET_ALARM_DOUBLE"></A>
<H3>
get_alarm_double</H3>
Sets the following values:

<P>&nbsp;upper_alarm_limit = HIHI

<P>&nbsp;upper_warning_limit = HIGH

<P>&nbsp;lower_warning_limit = LOW

<P>&nbsp;lower_alarm_limit = LOLO

<HR>
<P>&nbsp;<A NAME="RECORD_PROCESSING"></A>
<H1>
12. Record Processing</H1>

<A NAME="PROCESS"></A>
<H2>
12.1. process()</H2>
The <TT>process()</TT> routine implements the following algorithm:

<P>&nbsp;
<DL>
<DD>
1. Fetch all arguments.</DD>


<P>&nbsp;
<DD>
2. Call routine aCalcPerform(), which calculates VAL from the postfix version
of the expression given in CALC. If aCalcPerform() returns success, UDF
is set to FALSE.</DD>


<P>&nbsp;
<DD>
3. Check alarms. This routine checks to see if the new VAL causes the alarm
status and severity to change. If so, NSEV, NSTA and LALM are set. It also
honors the alarm hysteresis factor (HYST). Thus the value must change by
at least HYST before the alarm status and severity changes.</DD>


<P>&nbsp;
<DD>
4. Determine if the Output Execution Option (OOPT) is met. If it is met,
either execute the output link (and output event) immediately (if ODLY
= 0), or schedule a callback to do so after the specified interval. See the
explanation for the <TT>execOutput()</TT> routine below.</DD>


<P>&nbsp;
<DD>
5. Check to see if monitors should be invoked.</DD>


<P>&nbsp;
<UL>
<LI>
Alarm monitors are invoked if the alarm status or severity has changed.</LI>


<P>&nbsp;
<LI>
Archive and value change monitors are invoked if ADEL and MDEL conditions
are met.</LI>


<P>&nbsp;
<LI>
Monitors for A-L and AA-LL are checked whenever other monitors are invoked.</LI>


<P>&nbsp;
<LI>
NSEV and NSTA are reset to 0.</LI>


<P>&nbsp;</UL>

<DD>
6. If no output delay was specified, scan forward link if necessary, set
PACT FALSE, and return.</DD>


<P>&nbsp;</DL>
<A NAME="EXEC_OUTPUT"></A>
<H2>
12.2. execOutput()</H2>

<DL>
<DD>
1. If DOPT field specifies the use of OCAL, call the routine aCalcPerform
for the postfix version of the expression in OCAL. Otherwise, use VAL.</DD>


<P>&nbsp;
<DD>
2. If the Alarm Severity is INVALID, follow the option as designated by
the field IVOA.</DD>


<P>&nbsp;
<DD>
3. If the Alarm Severity is not INVALID or IVOA specifies "Continue Normally",
call device support to write the value of OVAL to device or PV specified by
the OUT link, and post the event in OEVT (if non-zero).</DD>


<P>&nbsp;
<DD>
4. If an output delay was implemented, process the forward link.</DD>


<P>&nbsp;</DL>


<HR>
<ADDRESS>
Tim Mooney</ADDRESS>

</BODY>
</HTML>
